﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace FSM
{
    /// <summary>
    /// 状态机运行状态
    /// </summary>
    public enum FSM_STATE_E
    {
        /// <summary>
        /// 运行态
        /// </summary>
        RUNNING = 0,
        /// <summary>
        /// 故障态
        /// </summary>
        FAULT = 1,
    }

    /// <summary>
    /// 状态机触发事件
    /// </summary>
    public enum TRIG_EVENT_E
    {
        /// <summary>
        /// 传感器故障事件
        /// </summary>
        SENSOR_FAULT = 0,
        /// <summary>
        /// 传感器故障恢复事件
        /// </summary>
        SENSOR_RESUME = 1,
    }

    /// <summary>
    /// 事件触发消息结构
    /// </summary>
    public struct MSG_EVENT_TRIG_T {
        /// <summary>
        /// 事件触发传感器端口
        /// </summary>
        public uint eDevPort;
        /// <summary>
        /// 事件触发类型
        /// </summary>
        public TRIG_EVENT_E eEventType;
    }

    /// <summary>
    /// 探测器
    /// </summary>
    public struct DEV_DET_T
    {
        /// <summary>
        /// 事件触发队列
        /// </summary>
        public Queue<MSG_EVENT_TRIG_T> stEventQue;
    }

    public static class App
    {
        /// <summary>
        /// 创建监控探测器实例
        /// </summary>
        public static DEV_DET_T g_stDetIns;

        /// <summary>
        /// 状态机变量
        /// </summary>
        public static sFSM g_stFsm;

        /// <summary>
        /// 状态迁移表
        /// </summary>
        public static List<sFsmTable> g_stFsmTable = new List<sFsmTable>()
        {
            new sFsmTable(){
                Event=(int)TRIG_EVENT_E.SENSOR_FAULT,
                CurState=(int)FSM_STATE_E.RUNNING,
                EventActFun=ActFunc_FaultEvent,
                NextState=(int)FSM_STATE_E.FAULT },

            new sFsmTable(){
                Event=(int)TRIG_EVENT_E.SENSOR_RESUME,
                CurState=(int)FSM_STATE_E.FAULT,
                EventActFun=ActFun_FaultResumeEvent,
                NextState=(int)FSM_STATE_E.RUNNING }

        };

        /// <summary>
        /// 状态迁移表长度
        /// </summary>
        /// <param name="stFsmTable"></param>
        /// <returns></returns>
        public static int FSM_TABLE_MAX_NUM(this List<sFsmTable> stFsmTable)
        {
            return (int)stFsmTable.Count();
        }

        public static void App_Init()
        {
            g_stDetIns.stEventQue = new Queue<MSG_EVENT_TRIG_T>();

            //初始化状态机
            Fsm.FSM_Init(ref g_stFsm, g_stFsmTable, g_stFsmTable.FSM_TABLE_MAX_NUM(), (int)FSM_STATE_E.RUNNING);
        }


        /// <summary>
        /// 触发故障事件动作函数
        /// </summary>
        /// <param name="parm"></param>
        public static void ActFunc_FaultEvent(IntPtr parm)
        {
            Console.WriteLine($"触发故障事件动作");

            //模拟故障恢复动作
            Console.Write($"故障恢复中");
            int time = 5;
            while ((time--) > 0)
            {
                Console.Write(".");
                Thread.Sleep(1000);
            }
            Console.WriteLine("");


            TestRESUME_Event();
        }

        /// <summary>
        /// 故障恢复事件动作函数
        /// </summary>
        /// <param name="parm"></param>
        public static void ActFun_FaultResumeEvent(IntPtr parm)
        {
            Console.WriteLine($"故障修复");
        }

        public static void FsmEventHandleTask()
        {
            if (g_stDetIns.stEventQue.Count > 0)
            {
                /* 取出触发事件队列中的事件 */
                MSG_EVENT_TRIG_T TrigMsg = g_stDetIns.stEventQue.Dequeue();

                /* 在其它模块中改变触发事件，即可完成相应动作的执行 */
                Fsm.FSM_EventHandle(ref g_stFsm, (int)TrigMsg.eEventType, (IntPtr)TrigMsg.eDevPort);
            }

        }

        /// <summary>
        /// 更新触发事件
        /// </summary>
        /// <param name="stTrigEventMsg"></param>
        public static void Elec_UpdateEvent(MSG_EVENT_TRIG_T stTrigEventMsg)
        {
            g_stDetIns.stEventQue.Enqueue(stTrigEventMsg);
        }

        /// <summary>
        /// 测试事件方法
        /// </summary>
        public static void TestFAULT_Event()
        {
            MSG_EVENT_TRIG_T stTrigEventMsg = new MSG_EVENT_TRIG_T();

            //触发故障事件
            Console.WriteLine($"发生故障事件");
            stTrigEventMsg.eEventType = TRIG_EVENT_E.SENSOR_FAULT;
            Elec_UpdateEvent(stTrigEventMsg);
        }


        /// <summary>
        /// 测试事件方法
        /// </summary>
        public static void TestRESUME_Event()
        {
            MSG_EVENT_TRIG_T stTrigEventMsg = new MSG_EVENT_TRIG_T();

            //触发故障事件
            Console.WriteLine($"故障修复");
            stTrigEventMsg.eEventType = TRIG_EVENT_E.SENSOR_RESUME;
            Elec_UpdateEvent(stTrigEventMsg);
        }
    }


    public class Program
    {
        
        static void Main(string[] args)
        {
            Console.WriteLine($"Start");
            App.App_Init();
            App.TestFAULT_Event();
            Task.Run(() =>
            {


                while (true)
                {
                    App.FsmEventHandleTask();
                    Thread.Sleep(100);
                }
            }).Wait();
        }

        

    }



}
